#include "Camera.h"
#include <MCWorld.h>

Camera::Camera(float SCR_WIDTH, float SCR_HEIGHT,
glm::vec3 position, glm::vec3 up) 
: Front(glm::vec3(0.0f, 1.0f, 0.0f)), MovementSpeed(6.f), MouseSensitivity(0.2f), Zoom(45)
{
    position = position;
    WorldUp = up;

    projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f,MCWorld::GetObservationRange()*16.f);
    updateCameraVectors();
}
// constructor with scalar values
Camera::Camera(float SCR_WIDTH, float SCR_HEIGHT,float posX, float posY, float posZ, float upX, float upY, float upZ) : 
Front(glm::vec3(0.0f, 1.0f, 0.0f)), MovementSpeed(2.5f), MouseSensitivity(0.2f), Zoom(45)
{
    position = glm::vec3(posX, posY, posZ);
    WorldUp = glm::vec3(upX, upY, upZ);

    projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f,MCWorld::GetObservationRange()*16.f);
    updateCameraVectors();
}
// returns the view matrix calculated using Euler Angles and the LookAt Matrix

// processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
void Camera::ProcessKeyboard(Camera_Movement direction, float deltaTime)
{
    float velocity = MovementSpeed * deltaTime;
    if (direction == FORWARD)
        position += Front * velocity;
    if (direction == BACKWARD)
        position -= Front * velocity;
    if (direction == LEFT)
        position -= Right * velocity;
    if (direction == RIGHT)
        position += Right * velocity;
}
// processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void Camera::ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch)
{
    xoffset *= MouseSensitivity;
    yoffset *= MouseSensitivity;
    this->AddRotation(yoffset,0 ,-xoffset); 
 
    if (constrainPitch)
    {
        if (this->rotation.x > 89.0f && this->rotation.x < 180.0f)
            this->rotation.x  = 89.0f;
        if (this->rotation.x > 180.0f && this->rotation.x <360.f -89.0f)
            this->rotation.x  = 360.f -89.0f;
    }
    updateCameraVectors();
}


void Camera::updateCameraVectors()
{
    glm::vec4 front;
    auto rotatex=glm::rotate(glm::mat4(1.0),glm::radians(this->rotation.x),glm::vec3(1.0f, 0.0f, 0.0f));
    auto rotatez=glm::rotate(glm::mat4(1.0),glm::radians(this->rotation.z),glm::vec3(0.0f, 0.0f, 1.0f));
    front = rotatez*rotatex*glm::vec4(0.0f, 1.0f, 0.0f, 0.0f);
    Front = glm::normalize(glm::vec3(front.x, front.y, front.z));
    // also re-calculate the Right and Up vector
    // normalize the vectors, because their length gets closer to 
    // 0 the more you look up or down which results in slower movement.
    Right = glm::normalize(glm::cross(Front, WorldUp));  
    Up    = glm::normalize(glm::cross(Right, Front));
}
